package editor;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import editor.manager.SideBarManager;
import editor.project.Project;
import editor.project.ProjectFile;

/**
 * Communicates between settings on the file store and in memory.
 * On load initialises objects from settings.
 * On save puts all save-able objects to the file store.
 * 
 * @author Mark Dessain
 */
public class EditorSettings 
{

	// Location of the Settings XML file
	private final String SETTINGSXMLFILE = "settings.xml";

	// XML Main Document and Root
	private Document doc;
	private Element root;

	// Element for the projects and settings
	private List<Element> projects;
	private List<Element> settings;
	private List<Element> files;

	// Lists with the relevant data
	private ArrayList<Project> projectList = new ArrayList<Project>();
	private ArrayList<ProjectFile> fileList = new ArrayList<ProjectFile>();
	private HashMap<String, String> settingsList = new HashMap<String, String>();

	
	/**
	 * Loads all settings, removes any corrupt data.
	 */
	public EditorSettings()
	{        
		reload();
	}

	/**
	 * Loads all the files from XML into memory.
	 */
	@SuppressWarnings("unchecked")
	private void loadFiles()
	{
		fileList.clear();
		files = root.getChild("files").getChildren("file");
		
		System.out.println("-------");

		for(Element file: files)
		{
			System.out.println("File: " + file);
			String projectName = file.getChildText("project");
			String directory = file.getChildText("directory");
			
			System.out.println(directory);
			
			for(Project project: projectList)
			{

				if(project.getName().equals(projectName))
				{
					Project selectedProject = project;

					System.out.println(" - Project: " + project);
							
					for(ProjectFile projectFile: selectedProject.getFiles())
					{
						

						System.out.println(" - - ProjectFile: " + projectFile);
						
						if(projectFile.getAbsolutePath().equals(directory))
						{
							fileList.add(projectFile);
						}
					}
				}
			}
			
		}		
	}
	
	/**
	 * Removes all current files from settings and saves all open files to the file store.
	 */
	private void saveFiles()
	{
		Element projectSetting = root.getChild("files");	
		projectSetting.removeChildren("file");

		
		for(ProjectFile file: fileList)
		{
			projectSetting.addContent(file.getXMLElement());
		}
	}
	
	/**
	 * Loads all the projects from XML into memory.
	 */
	@SuppressWarnings("unchecked")
	private void loadProjects()
	{
		projectList.clear();
		projects = root.getChild("projects").getChildren("project");

		for(Element project: projects)
		{
			String name = project.getChildText("name");
			String directory = project.getChildText("directory");

			Project loadProject = new Project(name, directory);

			if(!checkProjectDuplicate(loadProject) && loadProject.isDirectory())
			{
				projectList.add(loadProject);
				SideBarManager.projectManager.loadProject(loadProject);
			}
		}
		
		SideBarManager.projectManager.refresh();	
	}

	/**
	 * Removes all current projects from settings and saves all open projects to the file store.
	 */
	private void saveProjects()
	{
		Element projectSetting = root.getChild("projects");	
		projectSetting.removeChildren("project");

		for(Project project: projectList)
		{
			projectSetting.addContent(project.getXMLElement());
		}
	}    

	/**
	 * Loads all the settings from XML into memory.
	 */
	@SuppressWarnings("unchecked")
	private void loadSettings()
	{
		settingsList.clear();
		settings = projects = root.getChild("settings").getChildren();

		for(Element setting: settings)
		{
			String name = setting.getName();
			String value = setting.getText();

			settingsList.put(name, value);
		}    	
	}

	/**
	 * Removes all current settings from settings and saves all settings to the file store.
	 */
	private void saveSettings()
	{
		Element settings = root.getChild("settings");	
		settings.removeContent();

		Set<Entry<String, String>> set = settingsList.entrySet();
		Iterator<Entry<String, String>> i = set.iterator();

		while(i.hasNext()){
			Entry<String, String> me = i.next();
			Element setting = new Element(me.getKey().toString());
			setting.setText(me.getValue().toString());
			settings.addContent(setting);
		}
	}

	/**
	 * @param project Project which is been checked for existence.
	 * @return True if the Project already exists in the settings, False if it does not.
	 */
	public boolean checkProjectDuplicate(Project project)
	{
		boolean duplicate = false;

		for(Project checkProject: projectList)
		{
			if(checkProject.equals(project))
			{
				duplicate = true;
			}
		}

		return duplicate;
	}
	
	/**
	 * @param file adds file to the settings and saves to file store
	 */
	public void addFile(ProjectFile file)
	{
		fileList.add(file);
		saveFiles();
		saveXML();
	}
	
	/**
	 * @param file removes file to the settings and saves to file store
	 */
	public void removeFile(ProjectFile file)
	{
		fileList.remove(file);
		saveFiles();
		saveXML();
	}
	
	/**
	 * removes all the files from the settings and saves to file store
	 */
	public void removeAllFiles()
	{
		fileList.clear();
		saveFiles();
		saveXML();
	}

	/**
	 * @param project adds project to the settings and saves to file store
	 */
	public void addProject(Project project)
	{ 	
		projectList.add(project);
		saveProjects();
		saveXML();
	}

	/**
	 * @param project removes project to the settings and saves to file store
	 */
	public void removeProject(Project project)
	{
		projectList.remove(project);
		saveProjects();
		saveXML();
	}

	/**
	 * @param name setting key
	 * @param value setting value
	 */
	public void changeSetting(String name, String value)
	{
		settingsList.put(name, value);
		saveSettings();
		saveXML();
	}

	/**
	 * @return list of all projects
	 */
	public ArrayList<Project> getProjects()
	{
		return projectList;
	}
	
	/**
	 * @return list of all files
	 */
	public ArrayList<ProjectFile> getFiles()
	{
		return fileList;
	}

	/**
	 * @return list of all settings
	 */
	public HashMap<String, String> getSettings()
	{
		return settingsList;
	}

	/**
	 * @param key setting key
	 * @return setting value for the key
	 */
	public String getSetting(String key)
	{
		return settingsList.get(key);
	}
	
	/**
	 * loads the XML settings into memory
	 */
	private void loadXML()
	{
		try {
			SAXBuilder builder = new SAXBuilder(false);
			doc = builder.build(new File(SETTINGSXMLFILE));
			root = doc.getRootElement();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}     	
	}

	/**
	 * saves memory onto file store
	 */
	private void saveXML()
	{
		try {
			XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
			FileWriter writer = new FileWriter(SETTINGSXMLFILE);
			outputter.output(doc, writer);
			writer.close();
		} catch (java.io.IOException e) {
			e.printStackTrace();
		}   	
	}

	/**
	 * does a reload of settings
	 */
	public void reload()
	{
		loadXML();
		loadProjects();   
		loadFiles();
		loadSettings();

		saveSettings();
		saveFiles();
		saveProjects();
		saveXML();  
	}
}